Hands-On Interactive Session & Free Compiler Guide
Concept: A RESTful API uses standard HTTP verbs (GET, POST, PUT, DELETE) to perform operations on resources (like Products, Users). It is stateless and returns JSON.
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
namespace MyWebApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
private static List<Product> _products = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Price = 1200 },
new Product { Id = 2, Name = "Mouse", Price = 25 }
};
// GET: api/products (Read All)
[HttpGet]
public ActionResult<IEnumerable<Product>> GetProducts()
{
return Ok(_products);
}
// GET: api/products/1 (Read One)
[HttpGet("{id}")]
public ActionResult<Product> GetProduct(int id)
{
var product = _products.FirstOrDefault(p => p.Id == id);
if (product == null) return NotFound(); // 404
return Ok(product); // 200
}
// POST: api/products (Create)
[HttpPost]
public ActionResult<Product> CreateProduct([FromBody] Product product)
{
product.Id = _products.Max(p => p.Id) + 1;
_products.Add(product);
return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product); // 201
}
// DELETE: api/products/1 (Delete)
[HttpDelete("{id}")]
public IActionResult DeleteProduct(int id)
{
var product = _products.FirstOrDefault(p => p.Id == id);
if (product == null) return NotFound();
_products.Remove(product);
return NoContent(); // 204
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
Since online fiddles are primarily for console apps, let's write a C# program that mimics a REST API routing system. This helps you understand the logic behind HTTP verbs and status codes before deploying to a real server.
Copy the code below, paste it into dotnetfiddle.net, and hit Run. This simulates a client calling your API.
using System;
using System.Collections.Generic;
using System.Linq;
// 1. Define the Model
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
// 2. Simulate a Web API Controller
public class ProductsApiController
{
private static List<Product> _db = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Price = 1200 },
new Product { Id = 2, Name = "Mouse", Price = 25 }
};
// GET /api/products
public void GetAll()
{
Console.WriteLine("HTTP 200 OK:");
foreach(var p in _db) Console.WriteLine($" - {p.Id}: {p.Name} (${p.Price})");
}
// POST /api/products
public void Create(string name, decimal price)
{
var newProduct = new Product { Id = _db.Max(p => p.Id) + 1, Name = name, Price = price };
_db.Add(newProduct);
Console.WriteLine($"HTTP 201 Created: Added {newProduct.Name} with ID {newProduct.Id}");
}
// DELETE /api/products/{id}
public void Delete(int id)
{
var product = _db.FirstOrDefault(p => p.Id == id);
if (product != null)
{
_db.Remove(product);
Console.WriteLine($"HTTP 204 No Content: Deleted ID {id}");
}
else
{
Console.WriteLine($"HTTP 404 Not Found: ID {id} does not exist.");
}
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("--- Starting Simulated Web API Session ---\n");
var api = new ProductsApiController();
// Simulate Client Requests
api.GetAll();
Console.WriteLine();
api.Create("Keyboard", 75);
Console.WriteLine();
api.GetAll();
Console.WriteLine();
api.Delete(1);
Console.WriteLine();
api.Delete(99); // Triggers 404
Console.WriteLine();
api.GetAll();
}
}
Concept: Middleware are components that handle requests and responses in a pipeline. Each component can process the request before passing it to the next component (and process the response on the way back).
using System.Diagnostics;
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestTimingMiddleware> _logger;
public RequestTimingMiddleware(RequestDelegate next, ILogger<RequestTimingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var stopwatch = Stopwatch.StartNew();
// Pass request to the next middleware in the pipeline
await _next(context);
stopwatch.Stop();
var elapsedMs = stopwatch.ElapsedMilliseconds;
// Log the time taken after the response comes back
_logger.LogInformation($"Request {context.Request.Path} took {elapsedMs} ms.");
}
}
// --- Registration in Program.cs ---
// var app = builder.Build();
// app.UseMiddleware<RequestTimingMiddleware>(); // Register here!
// app.UseAuthentication();
// app.UseAuthorization();
// app.MapControllers();
// app.Run();
Concept: JSON Web Tokens (JWT) are used to securely transmit information. The server issues a token upon login, and the client sends it in the HTTP Header for protected routes.
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// 1. Configure JWT Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "MyApp",
ValidAudience = "MyAppUsers",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThisIsAVerySecretKey1234567890!"))
};
});
builder.Services.AddControllers();
var app = builder.Build();
// 2. Add Middleware to the pipeline
app.UseAuthentication(); // Must be BEFORE UseAuthorization
app.UseAuthorization();
app.MapControllers();
app.Run();
// --- How to protect a Controller ---
// [Authorize] // Add this attribute to your Controller class or specific Action
// [ApiController]
// [Route("api/[controller]")]
// public class SecureController : ControllerBase { ... }
Concept: ASP.NET Core uses the Generic Host to manage app startup and lifetime. It includes Kestrel, a cross-platform, lightning-fast embedded HTTP server. Unlike old .NET, Kestrel is built directly into the application process.
var builder = WebApplication.CreateBuilder(args);
// Configure Kestrel (Embedded HTTP Server) directly in code
builder.WebHost.ConfigureKestrel(serverOptions =>
{
// Set connection limits
serverOptions.Limits.MaxConcurrentConnections = 100;
serverOptions.Limits.MaxRequestBodySize = 10 * 1024; // 10 MB
// You can also configure specific endpoints/ports here
// serverOptions.ListenAnyIP(5000);
// serverOptions.ListenAnyIP(5001, listenOptions => listenOptions.UseHttps());
});
var app = builder.Build();
// The Host manages the lifetime. app.Run() starts the Kestrel server.
app.MapGet("/", () => "Hello from Kestrel Embedded Server!");
app.Run();
dotnet new webapi -n MyFirstApicd MyFirstApidotnet runhttp://localhost:5000 or https://localhost:5001). You can then test your API using Postman or Swagger (built-in at /swagger).